﻿using System;
using System.Text;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Data.SQLite;

namespace ServerRPG
{
    static class Server
    {
        public static string _serverName;
        public static int _serverPort;

        private static bool server = true; // Server OK.
        private static TcpListener _serverListener;
        private static List<Client> _clients = new List<Client>();
        private static List<Thread> _clientsThreads = new List<Thread>();

        private static Thread _commandThread;
        public static string commandList;

        public static CreatureManager creatureManager;

        /// <summary>
        /// Инициализирует сервер.
        /// </summary>
        public static void Start()
        {
            ConfigurationManager.FilePath = "server.config"; 
            #region Конфиг по умолчанию
            ConfigurationManager.SetDefaultConfig(new string[] {
                "# Main",
                "",
                "ServerName = Test RPG Server",
                "",
                "# Settings",
                "",
                "port = 49337",
                "",
                "# Paths",
                "",
                "DBPath = DB\\",
                "DBName = main.db",
                "",
                "LogsPath = Logs\\"
            });
            #endregion

            _serverName = ConfigurationManager.GetProperty("ServerName");
            _serverPort = Convert.ToInt32(ConfigurationManager.GetProperty("port"));

            LogManager.FilePath = ConfigurationManager.GetProperty("LogsPath");
            LogManager.FileName = DateTime.Now.ToShortDateString() + ".log";

            LogManager.WriteExt("Сервер стартовал.");

            DBManager.Path = ConfigurationManager.GetProperty("DBPath");
            DBManager.Name = ConfigurationManager.GetProperty("DBName");

            _commandThread = new Thread(new ParameterizedThreadStart(CommandThread));
            _commandThread.Start();

            #region command 'help' list
            commandList = "> Commands:\n" +
                          "> \texit, stop, shut, shutdown - Завершение работы сервера;\n" +
                          "> \trestart - Перезапуск сервера;\n" +
                          "> \tsend, message - Передача сообщения всем клиентам;\n" +
                          "> \treg - Регистрация нового пользователя;\n" +
                          "> \tdbReg - Создание новой базы данных с паролем по умолчанию;\n" +
                          "> \tdbImport - Импортирование скриптов из sql-файла\n;" +
                //"> \tdbSetPassword - Установка нового пароля на базу данных;\n" +
                //"> \tdbRemovePassword - Удаление пароля с базы данных;\n" +
                          "> \tban - Блокирование пользователя;\n" +
                          "> \tunban - Разблокирование пользователя;\n" +
                          "> \tclear - 'Очищение' экрана консоли.";
            #endregion

            creatureManager = new CreatureManager();
            LogManager.WriteExt("Загружено " + creatureManager.creatureList.Count + " существ в память.");

            server = true;
            Listen();
        }
        /// <summary>
        /// Добавление клиента в список клиентов.
        /// </summary>
        /// <param name="client">Экземпляр клиента</param>
        public static void AddClient(Client client)
        {
            _clients.Add(client);
        }
        /// <summary>
        /// Получить кол-во клиентов в списке.
        /// </summary>
        /// <returns>Возвращает количество клиентов в списке.</returns>
        public static int GetClients()
        {
            if (_clients != null)
            {
                int n = 0;
                foreach (Client c in _clients)
                    if (c.username != String.Empty)
                        n++;
                return n;
            }
            else
                return -1;
        }
        /// <summary>
        /// Получить список клиентов.
        /// </summary>
        /// <returns>Возвращает список клиентов.</returns>
        public static List<Client> GetClientsList()
        {
            return _clients;
        }
        /// <summary>
        /// Удалить клиента из списка.
        /// </summary>
        /// <param name="client"></param>
        public static void RemoveClient(Client client)
        {
            _clients.Remove(client);
        }
        /// <summary>
        /// Передать сообщение все клиентам.
        /// </summary>
        /// <param name="msg"></param>
        public static void WriteToAll(string msg)
        {
            foreach (Client tcp in _clients)
            {
                tcp.Write(msg);
            }
        }
        /// <summary>
        /// Перезапустить сервер.
        /// </summary>
        public static void Restart()
        {
            Stop();
            LogManager.WriteExt("Перезапуск сервера.");
            Start();
        }
        /// <summary>
        /// Остановить работу сервера.
        /// </summary>
        public static void Stop()
        {
            // Закрыть все потоки.
            foreach (Client client in _clients)
            {
                client.Stop();
            }
            foreach (Thread thread in _clientsThreads)
            {
                if (thread.IsAlive)
                    thread.Abort();
            }
            server = false;
            _serverListener.Stop();
            creatureManager.Stop();

            LogManager.WriteExt("Сервер остановлен.");
            System.Threading.Thread.Sleep(150);
        }
        /// <summary>
        /// Выключить сервер.
        /// </summary>
        public static void Shutdown()
        {
            // Закрыть все потоки.
            foreach (Client client in _clients)
            {
                client.Stop();
            }
            foreach (Thread thread in _clientsThreads)
            {
                if (thread.IsAlive)
                    thread.Abort();
            }
            server = false;
            _serverListener.Stop();

            LogManager.Write("Сервер остановлен.");
            System.Threading.Thread.Sleep(150);

            creatureManager.Stop();
            _commandThread.Abort();
        }
        /// <summary>
        /// Начать прослушивание TCP.
        /// </summary>
        private static void Listen()
        {
            try
            {
                _serverListener = new TcpListener(IPAddress.Any, _serverPort);
            }
            catch (Exception ex)
            {
                LogManager.WriteExt(ex.Message);
                return;
            }

            _serverListener.Start();

            while (server)
            {
                if (!_serverListener.Pending())
                {
                    Thread.Sleep(500);
                    continue;
                }
                try
                {
                    TcpClient client = _serverListener.AcceptTcpClient();
                    if (client != null)
                    {
                        LogManager.WriteExt("Клиент подключен: " + client.Client.RemoteEndPoint.ToString());
                        _clientsThreads.Add(new Thread(new ParameterizedThreadStart(ClientThread)));
                        _clientsThreads[_clientsThreads.Count - 1].Start(client);
                    }
                }
                catch (Exception ex)
                {
                    LogManager.WriteExt(ex.Message);
                    break;
                }

            }
        }
        /// <summary>
        /// Потоки для клиентов.
        /// </summary>
        /// <param name="stateInfo"></param>
        private static void ClientThread(object stateInfo)
        {
            new Client((TcpClient)stateInfo);
        }
        /// <summary>
        /// Поток для команд сервера.
        /// </summary>
        /// <param name="stateInfo"></param>
        private static void CommandThread(object stateInfo)
        {
            while (server)
            {
                string com = Console.ReadLine();
                switch (com)
                {
                    case "exit":
                    case "stop":
                    case "shut":
                    case "shutdown":
                        {
                            Shutdown();
                        }
                        break;
                    case "restart":
                        {
                            Restart();
                        }
                        break;
                    case "send":
                    case "message":
                        {
                            Console.Write("> Передать всем сообщение: ");
                            WriteToAll(Console.ReadLine());
                            LogManager.WriteExt("Сообщение передано {" + _clients.Count.ToString() + "} игрокам.");
                        }
                        break;
                    case "reg":
                        {
                            Console.Write("> Регистрация нового аккаунта (log;pas): ");
                            CommandParser.Separator = ";";
                            string reg = Console.ReadLine();
                            if (AccountManager.Add(CommandParser.GetCommand(reg, 0), CommandParser.GetCommand(reg, 1)))
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                            CommandParser.Separator = "|";
                        }
                        break;
                    case "dbReg":
                        {
                            if (DBManager.Create())
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                        }
                        break;
                    case "dbImport":
                        {
                            Console.Write("> Файл для импортирования sql-скрипта: ");
                            if (DBManager.Import(Console.ReadLine()))
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                        }
                        break;
                    /*case "dbSetPassword":
                        {
                            Console.Write("> Новый пароль: ");
                            if (DBManager.SetPassword(Console.ReadLine()))
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                        }
                        break;
                    case "dbRemovePassword":
                        {
                            Console.Write("> Старый пароль: ");
                            if (DBManager.RemovePassword(Console.ReadLine()))
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                        }
                        break;*/
                    case "ban":
                        {
                            Console.Write("> Пользователь: ");
                            if (AccountManager.SetLevel(Console.ReadLine(), -1))
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                        }
                        break;
                    case "unban":
                        {
                            Console.Write("> Пользователь: ");
                            if (AccountManager.SetLevel(Console.ReadLine(), 1))
                                Console.WriteLine("> Удачка.");
                            else
                                Console.WriteLine("> Никак не получается.");
                        }
                        break;
                    case "clear":
                        Console.Clear();
                        break;
                    case "help":
                        Console.WriteLine(commandList);
                        break;
                    default:
                        Console.WriteLine("> Неизвестная команда.");
                        break;
                }
            }
        }
    }
}